package org.example.sqlsession;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.example.config.Function;
import org.example.config.MapperBean;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

public class MyConfiguration {
    private static ClassLoader classLoader = ClassLoader.getSystemClassLoader();

    public Connection build(String resource) {
        try {
            Element rootElement = getRootElement(resource);
            return evalDataSource(rootElement);
        } catch (Exception e) {
            throw new RuntimeException("error occured while evaling xml " + resource);
        }
    }

    public MapperBean readMapper(String resource) {
        try {
            Element rootElement = getRootElement(resource);
            return evalMapper(rootElement);
        } catch (Exception e) {
            throw new RuntimeException("error occured while evaling xml " + resource);
        }
    }

    private Element getRootElement(String resource) throws DocumentException {
        InputStream resourceAsStream = classLoader.getResourceAsStream(resource);
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(resourceAsStream);
        return document.getRootElement();
    }

    private Connection evalDataSource(Element element) throws ClassNotFoundException, SQLException {
        if (!element.getName().equals("database")) {
            throw new RuntimeException("root should be <database>");
        }

        String driverClassName = null;
        String url = null;
        String username = null;
        String password = null;

        for (Object o : element.elements("property")) {
            Element e = (Element) o;
            String name = e.attributeValue("name");
            String value = e.getText();
            if (name == null || value == null) {
                throw new RuntimeException("property should contain name and value");
            }
            switch (name) {
                case "driverClassName":
                    driverClassName = value;
                    break;
                case "url":
                    url = value;
                    break;
                case "username":
                    username = value;
                    break;
                case "password":
                    password = value;
                    break;
                default:
                    throw new RuntimeException("dataase unknown name:" + name);
            }
        }

        Class.forName(driverClassName);
        return DriverManager.getConnection(url, username, password);
    }

    private MapperBean evalMapper(Element rootElement) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        MapperBean mapperBean = new MapperBean();
        ArrayList<Function> functions = new ArrayList<>();
        Iterator<Element> elementIterator = rootElement.elementIterator();
        while (elementIterator.hasNext()) {
            Function function = new Function();
            Element e = elementIterator.next();
            String id = e.attributeValue("id").trim();
            String resultType = e.attributeValue("resultType").trim();
            String funcName = e.getName().trim();
            String sql = e.getText().trim();
            function.setFuncName(id);
            function.setSalType(funcName);
            function.setSql(sql);
            function.setResultType(Class.forName(resultType).newInstance());
            functions.add(function);
        }
        mapperBean.setInterfaceName(rootElement.attributeValue("nameSpace"));
        mapperBean.setList(functions);
        return mapperBean;
    }

}
